#include <arch/processor.h>
#include <arch/lapic.h>
#include <arch/io.h>

#include <mm/heap.h>

#include <utils/list.h>

#include <drv/serial.h>

typedef struct {
	list_node_t node;

	processor_t info;
} processor_node_t;

typedef struct __packed {
	uint16_t limit0;
	uint16_t base0;
	uint8_t base1;
	unsigned flag : 4;
	unsigned desc_type : 1;
	unsigned privilege : 2;
	bool is_vaild : 1;
	unsigned limit1 : 4;
	unsigned usused : 4;
	uint8_t base2;
	uint32_t base3;
	uint32_t reserved;
} tss_entry_t;

static processor_node_t *processor_list;

void processor_register(uint32_t apic_id, uint32_t acpi_id, uint32_t flags) {
	processor_node_t *node = (processor_node_t *)mm_heap_zeroalloc(sizeof(processor_node_t));

	node->info.apic_id = apic_id;
	node->info.acpi_id = acpi_id;
	node->info.attribute = flags;

	if(__unlikely(!processor_list)) {
		processor_list = node;
	} else {
		list_append(&processor_list->node, &node->node);
	}
}

processor_t *processor_get(uint32_t apic_id) {
	processor_node_t *node = processor_list;

	while(node) {
		if(node->info.apic_id == apic_id) {
			return &node->info;
		}

		node = (processor_node_t *)list_next_node(&node->node);
	}

	return NULL;
}

processor_t *processor_get_current() {
	return processor_get(lapic_get_self_id());
}

void processor_foreach(void (*visitor)(processor_t *)) {
	processor_node_t *node = processor_list;

	while(node) {
		visitor(&node->info);

		node = (processor_node_t *)list_next_node(&node->node);
	}
}

void processor_self_init() {
	uint32_t apic_id = lapic_get_self_id();
	processor_t *current = processor_get(apic_id);

	io_wrmsr(MSR_GS_BASE, apic_id);
	io_wrmsr(MSR_KERN_GS_BASE, apic_id);

	// 初始化SSE
	uint64_t cr0, cr4;

	__asm__ volatile("mov %%cr0, %0" : "=r"(cr0));
	cr0 &= ~BIT(2);
	cr0 |= BIT(1);
	__asm__ volatile("mov %0, %%cr0" : : "r"(cr0));

	__asm__ volatile("mov %%cr4, %0" : "=r"(cr4));
	cr4 |= BIT(9) | BIT(10);
	__asm__ volatile("mov %0, %%cr4" : : "r"(cr4));

	// 初始化GDT
	current->gdt[0] = 0;
	current->gdt[GDT_KERNEL_CS_IDX] = MAKE_GDT_CS64_ENTRY(0);
	current->gdt[GDT_USER_CS_IDX] = MAKE_GDT_CS64_ENTRY(3);
	current->gdt[GDT_USER_DS_IDX] = MAKE_GDT_DS64_ENTRY(3);
	current->gdt[GDT_TSS_IDX] = 0;
	current->gdt[GDT_TSS_IDX + 1] = 0;

	//	初始化TSS
	tss_entry_t *tss_entry = (tss_entry_t *)&current->gdt[GDT_TSS_IDX];
	uint32_t tss_limit = sizeof(tss_entry_t);
	uintptr_t tss_base = (uintptr_t)&current->tss;

	tss_entry->is_vaild = 1;
	tss_entry->desc_type = 0;
	tss_entry->privilege = 0;
	tss_entry->flag = 0x9;
	tss_entry->limit0 = (tss_limit & 0xffff);
	tss_entry->limit1 = (tss_limit >> 16) & 0b1111;
	tss_entry->base0 = (tss_base & 0xffff);
	tss_entry->base1 = (tss_base >> 16) & 0xff;
	tss_entry->base2 = (tss_base >> 24) & 0xff;
	tss_entry->base3 = (tss_base >> 32);

	struct __packed {
		uint16_t limit;
		uint64_t base;
	} gdtr = {
			.limit = sizeof(current->gdt) - 1,
			.base = (uint64_t)current->gdt,
	};

	__asm__ volatile(
			"cli;"
			"lgdt %0;"
			"pushq $1 << 3;"
			"leaq 3(%%rip), %%rax;"
			"pushq %%rax;"
			"lretq;"
			"mov $0, %%rax;"
			"mov %%rax, %%ds;"
			"mov %%rax, %%es;"
			"mov %%rax, %%fs;"
			"mov %%rax, %%gs;"
			"mov %%rax, %%ss;"
			"mov $4 << 3, %%rax;"
			"ltr %%rax" ::"m"(gdtr));

	current->idle_task = task_create_idle();
}